

import {parseJointLine} from './md5jointLineParser';
import {parseMd5Mesh} from "./md5MeshParser";
import {quat} from "gl-matrix";


export class Md5Header{

    version:string = "";
    commandLine:string = "";
    numJoint = -1;
    numMesh = -1;

    constructor(headerLines:string[]){
        if (headerLines.length < 1){
            throw `can not parse empty header`
        }

        let ilen = headerLines.length;
        let finishHeader = false;
        for (let i = 0;i < ilen && !finishHeader; ++i){
            let line = headerLines[i];
            let tokens = line.split(/\s+/g);
            if (tokens.length > 1){
                let name = tokens[0];
                let value = tokens[1];
                switch (name) {
                    case "MD5Version":
                        this.version = value;
                        break;
                    case "commandline":
                        this.commandLine = value;
                        break;
                    case "numJoints":
                        this.numJoint = parseInt(value);
                        break;
                    case "numMeshes":
                        this.numMesh = parseInt(value);
                        break;
                    case "joints":
                        finishHeader = true;
                        break;
                }
            }
        }

        // info
        console.log("header_info:\n",`version:${this.version},numJoint:${this.numJoint},numMesh:${this.numMesh}`);
    }
}


export class JointData{
    constructor(
        public name:string,
        public parentIdx:number,
        public x:number,
        public y:number,
        public z:number,
        public quat:quat
                ){
    }

    static quatFrom(a:number,b:number,c:number){
        // 这是 normalize?
        let q = quat.fromValues(a,b,c,0);
        let t = 1 - (a * a) - (b * b) - (c * c);
        if (t < 0){
            q[3] = 0
        }else{
            q[3] = -Math.sqrt(t);
        }
        return q;
    }
}

// md5 格式说明
// https://blog.csdn.net/sh15285118586/article/details/46548815
export interface IMd5Vert {
    vertexIdx:number,
    u:number,
    v:number,
    weightIdx:number, // 这个顶点在权重列表中的第一个权重的索引
    weightCount:number, // 这个顶点在权重列表中受影响的权重数量
}

export interface IMd5Tri {
    triIdx:number,
    i0:number,
    i1:number,
    i2:number
}

export interface IWeight {
    weightIdx:number,
    boneIdx:number,
    weightValue:number,
    offx:number,
    offy:number,
    offz:number,
}

export interface Md5Mesh {
    imagePath : string,

    numVerts: number,
    verts:Array<IMd5Vert>,

    numTris:number,
    tris:Array<IMd5Tri>,

    numWeights:number,
    weights:Array<IWeight>,
}
export class Md5Model {
    header:Md5Header | null = null;
    joints:Array<JointData> = [];
    meshs: Array<Md5Mesh> = [];

    static parseJointData(line:string):JointData | null{
        let info = parseJointLine(line);
        if (info){
            return new JointData(
                // @ts-ignore
                info.name,
                // @ts-ignore
                info.parentIdx,
                // @ts-ignore
                info.x,
                // @ts-ignore
                info.y,
                // @ts-ignore
                info.z,
                // @ts-ignore
                JointData.quatFrom(info.rx,info.ry,info.rz)
            )
        }
        return null
    }
}


export class Md5Parser{

    static parse(meshdata:string){
        let lines = meshdata.split("\n");
        if (lines.length < 1){
            throw `empty file!`
        }


        let result = new Md5Model();

        let headerEnd = false;
        let ilen = lines.length;
        let curLineNum = 0;
        for (let i = 0; i < ilen && !headerEnd; ++i){
            let line = lines[i];
            headerEnd = line.trim().endsWith("{");
            curLineNum = i;
        }

        if (!headerEnd){
            throw 'can not find header'
        }


        let headerLines = lines.slice(0,curLineNum);
        result.header = new Md5Header(headerLines);

        // 可能有空行,需要过滤掉
        let blockStart = 0;
        let inBlock = false;
        let blockId = "";
        for (let i = curLineNum; i < ilen; ++i){
            let line = lines[i];
            if (line.trim().endsWith("{")){
                blockStart = i;
                // joints?
                blockId = line.substring(0,line.lastIndexOf("{")).trim();
                inBlock = true;
            }else if (inBlock && line.trim().endsWith("}")){
                let blockBody = lines.slice(blockStart + 1,i);
                Md5Parser.parseBody(result,blockId,blockBody);
                inBlock = false;
            }
        }


        // 将result 里面的数据 转换成 verticeArray,normalArray,texCoordArray,indiceArray
        // TODO:

        return result
    }

    private static parseBody(result: Md5Model, blockId: string, blockBody: string[]) {
        switch (blockId) {
            case "joints":
                blockBody.forEach(line=>{
                    let data = Md5Model.parseJointData(line);
                    if (data){
                        result.joints.push(data);
                    }
                });
                // console.log('result.joints:',result.joints.length);
                break;
            case "mesh":
                // console.log('mesh:\n',blockBody.join('\n'));
                let info = parseMd5Mesh(blockBody);
                result.meshs.push(info);
                break;
        }
    }
}
